module MemController (if_mc_en, if_mc_addr, mc_if_data,
    mem_mc_rw, mem_mc_en, mem_mc_addr, mem_mc_data,
    mem_mc_en1h, mem_mc_en1l, mem_mc_en2h, mem_mc_en2l,
    mc_ram_addr, mc_ram_rw, mc_ram_en1h, mc_ram_data1h,
    mc_ram_en1l, mc_ram_data1l, mc_ram_en2h, mc_ram_data2h,
    mc_ram_en2l, mc_ram_data2l);

	// Fetch
	input [0:0] if_mc_en;
	input [31:0] if_mc_addr;
	output [31:0] mc_if_data;

	// Memory
	input [0:0] mem_mc_rw;
	input [0:0] mem_mc_en;
	input [31:0] mem_mc_addr;
	inout [31:0] mem_mc_data;
	input [0:0] mem_mc_en1h;
	input [0:0] mem_mc_en1l;
	input [0:0] mem_mc_en2h;
	input [0:0] mem_mc_en2l;

	// Ram
	output [31:0] mc_ram_addr;
	output [0:0] mc_ram_rw;
	output [0:0] mc_ram_en1h;
	inout  [7:0] mc_ram_data1h;
	output [0:0] mc_ram_en1l;
    inout  [7:0] mc_ram_data1l;
	output [0:0] mc_ram_en2h;
	inout  [7:0] mc_ram_data2h;
	output [0:0] mc_ram_en2l;
	inout  [7:0] mc_ram_data2l;

    // Auxiliary registers 
    reg [0:0] reg_mc_ram_rw;
    reg [0:0] reg_mc_ram_en1h;
    reg [0:0] reg_mc_ram_en1l;
    reg [0:0] reg_mc_ram_en2h;
    reg [0:0] reg_mc_ram_en2l;
    reg [31:0] reg_mc_ram_addr;
    reg [31:0] reg_mc_if_data;
    reg [31:0] reg_mem_mc_data;

    // MC <- input data
    assign mem_mc_data[31:24] = (mem_mc_en && !mem_mc_rw) ? (mem_mc_en1h == 0 ? 8'b0 : reg_mem_mc_data[31:24]) : (mem_mc_rw) ? 8'bz : 8'b0;
    assign mem_mc_data[23:16] = (mem_mc_en && !mem_mc_rw) ? (mem_mc_en1l == 0 ? 8'b0 : reg_mem_mc_data[23:16]) : (mem_mc_rw) ? 8'bz : 8'b0;
    assign mem_mc_data[15:8] = (mem_mc_en && !mem_mc_rw) ? (mem_mc_en2h == 0 ? 8'b0 : reg_mem_mc_data[15:8]) : (mem_mc_rw) ? 8'bz : 8'b0;
    assign mem_mc_data[7:0] = (mem_mc_en && !mem_mc_rw) ? (mem_mc_en2l == 0 ? 8'b0 : reg_mem_mc_data[7:0]) : (mem_mc_rw) ? 8'bz : 8'b0;

    // MC -> RAM data
    assign mc_ram_data1h = (!if_mc_en && mem_mc_en && mem_mc_rw) ? (mem_mc_en1h == 0 ? 8'bz : reg_mem_mc_data[31:24]) : 8'bz;
    assign mc_ram_data1l = (!if_mc_en && mem_mc_en && mem_mc_rw) ? (mem_mc_en1l == 0 ? 8'bz : reg_mem_mc_data[23:16]) : 8'bz;
    assign mc_ram_data2h = (!if_mc_en && mem_mc_en && mem_mc_rw) ? (mem_mc_en2h == 0 ? 8'bz : reg_mem_mc_data[15:8]) : 8'bz;
    assign mc_ram_data2l = (!if_mc_en && mem_mc_en && mem_mc_rw) ? (mem_mc_en2l == 0 ? 8'bz : reg_mem_mc_data[7:0]) : 8'bz;

    // IF data -> MC -> RAM data
    assign mc_if_data[31:24] = reg_mc_if_data[31:24];
    assign mc_if_data[23:16] = reg_mc_if_data[23:16];
    assign mc_if_data[15:8] = reg_mc_if_data[15:8];
    assign mc_if_data[7:0] = reg_mc_if_data[7:0];

    // MC -> RAM signs
    assign mc_ram_rw = reg_mc_ram_rw;
    assign mc_ram_addr = reg_mc_ram_addr;
    assign mc_ram_en1h = reg_mc_ram_en1h;
    assign mc_ram_en1l = reg_mc_ram_en1l;
    assign mc_ram_en2h = reg_mc_ram_en2h;
    assign mc_ram_en2l = reg_mc_ram_en2l;


    always @(*) begin

        if ((if_mc_en == 1'b1) && (mem_mc_en == 1'b0)) begin

            // Instruction Fetch -- IF
            reg_mc_ram_rw = 1'b0;
            reg_mc_ram_addr = if_mc_addr;

            // Instruction bytes
            reg_mc_ram_en1h = 1'b1;
            reg_mc_ram_en1l = 1'b1;
            reg_mc_ram_en2h = 1'b1;
            reg_mc_ram_en2l = 1'b1;

            reg_mc_if_data[31:24] = mc_ram_data1h;
            reg_mc_if_data[23:16] = mc_ram_data1l;
            reg_mc_if_data[15:8] = mc_ram_data2h;
            reg_mc_if_data[7:0] = mc_ram_data2l;

        end else begin
            
            // Memory access
            if (mem_mc_en == 1'b1) begin
            
                // Sign forwarding
                reg_mc_ram_addr = mem_mc_addr;
                reg_mc_ram_rw = mem_mc_rw;
                reg_mc_ram_en1h = mem_mc_en1h;
                reg_mc_ram_en1l = mem_mc_en1l;
                reg_mc_ram_en2h = mem_mc_en2h;
                reg_mc_ram_en2l = mem_mc_en2l;
                 
        		// Memory reading/writing
		        if (mem_mc_rw == 1'b1) begin
        		    reg_mem_mc_data = mem_mc_data;
                end else begin 
                    reg_mem_mc_data[31:24] = mc_ram_data1h;
                    reg_mem_mc_data[23:16] = mc_ram_data1l;
                    reg_mem_mc_data[15:8] = mc_ram_data2h;
		            reg_mem_mc_data[7:0] = mc_ram_data2l;
                end

            end else begin

                reg_mc_ram_en1h = 1'b0;
                reg_mc_ram_en1l = 1'b0;
                reg_mc_ram_en2h = 1'b0;
                reg_mc_ram_en2l = 1'b0;
         
            end
            
        end

    end

endmodule
